package com.arcvideo.acsplayer.app;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;

import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;

import android.app.Application;
import android.app.NotificationManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.util.Log;

import com.arcvideo.MediaPlayer.ModuleManager;
import com.arcvideo.MediaPlayer.ModuleManager.E_ARCH_TYPE;
import com.arcvideo.acsplayer.config.ApplicationConfig;
import com.arcvideo.acsplayer.httprequest.BaseHttpRequest;
import com.arcvideo.acsplayer.preference.SharePreferenceUtil;
import com.arcvideo.acsplayer.utils.AppInfoUtils;
import com.arcvideo.acsplayer.utils.DbUtil;
import com.arcvideo.acsplayer.utils.LogUtil;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.nostra13.universalimageloader.cache.disc.naming.Md5FileNameGenerator;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import com.nostra13.universalimageloader.core.assist.QueueProcessingType;

public class AcsPlayerApplication extends Application {
	private static String TAG = AcsPlayerApplication.class.getSimpleName();

	private static AcsPlayerApplication mInstance = null;

	private HttpClient mHttpClient = null;
	private static final String CHARSET = HTTP.UTF_8;

	private SharePreferenceUtil mSpUtil;
	private NotificationManager mNotificationManager;
	private Gson mGson;
	protected ImageLoader mImageLoader;

	private static String _strFileDir = null;
	private static String _strLibsDir = null;

	private static E_ARM_INTYPE _eARMInType = getArmInType();

	private static DbUtil mDbHelper = null;

	private void initDbHelper(Context appContext) {
		if (null == mDbHelper)
			mDbHelper = new DbUtil(appContext, ApplicationConfig.PLAYER_DB, null, 2);
	}

	private enum E_ARM_INTYPE {
		arm9e, arm11, neon,
	};

	public synchronized static AcsPlayerApplication getInstance() {
		return mInstance;
	}

	public static Context getAppContext() {
		if (mInstance != null) {
			return mInstance.getApplicationContext();
		}
		return null;
	}

	@Override
	public void onCreate() {
		LogUtil.d(TAG, "SuperVisorApplication");
		// CrashHandler.getInstance().init(this);
		initData();

		mInstance = this;
		BaseHttpRequest.initBaseHttpRequest();
		mHttpClient = createHttpClient();
		mImageLoader = createImageLoader();

		initDbHelper(this);
		CheckCPUinfo();
		copyPlayerIni();
		LoadLibraray();

		super.onCreate();

	}

	@Override
	public void onTerminate() {
		// TODO Auto-generated method stub
		super.onTerminate();
		shutdownHttpClient();
		mImageLoader.clearDiscCache();
	}

	@Override
	public void onLowMemory() {
		// TODO Auto-generated method stub
		super.onLowMemory();
		shutdownHttpClient();
		mImageLoader.clearDiscCache();
	}

	private HttpClient createHttpClient() {
		HttpParams params = new BasicHttpParams();
		// ���û�������
		HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
		HttpProtocolParams.setContentCharset(params, CHARSET);
		HttpProtocolParams.setUseExpectContinue(params, true);
		// ��ʱ����
		/* �����ӳ���ȡ���ӵĳ�ʱʱ�� */
		ConnManagerParams.setTimeout(params, 5000);
		/* ���ӳ�ʱ */
		HttpConnectionParams.setConnectionTimeout(params, 15000);
		/* ����ʱ */
		HttpConnectionParams.setSoTimeout(params, 15000);
		// ����HttpClient֧��HTTp��HTTPS����ģʽ
		SchemeRegistry schReg = new SchemeRegistry();
		schReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
		schReg.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));

		HttpProtocolParams.setUserAgent(params, AppInfoUtils.getUserAgent());

		// ʹ���̰߳�ȫ�����ӹ���������HttpClient
		ClientConnectionManager conMgr = new ThreadSafeClientConnManager(params, schReg);
		HttpClient client = new DefaultHttpClient(conMgr, params);
		return client;
	}

	public HttpClient getHttpClient() {
		if (mHttpClient == null) {
			mHttpClient = createHttpClient();
		}
		return mHttpClient;
	}

	public ImageLoader createImageLoader() {
		ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(this).threadPriority(Thread.NORM_PRIORITY - 2)
				.denyCacheImageMultipleSizesInMemory().discCacheFileNameGenerator(new Md5FileNameGenerator())
				.tasksProcessingOrder(QueueProcessingType.LIFO).build();
		ImageLoader.getInstance().init(config);

		return ImageLoader.getInstance();
	}

	public ImageLoader getImageLoader() {
		if (mImageLoader == null) {
			mImageLoader = createImageLoader();
		}
		return mImageLoader;
	}

	private void shutdownHttpClient() {
		if (mHttpClient != null && mHttpClient.getConnectionManager() != null) {
			mHttpClient.getConnectionManager().shutdown();
			mHttpClient = null;
		}
	}

	private void initData() {
		// ��ת��û�� @Expose ע����ֶ�
		mGson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
		mSpUtil = new SharePreferenceUtil(this, ApplicationConfig.SP_FILE_NAME);

		mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
	}

	public synchronized Gson getGson() {
		if (mGson == null)
			// ��ת��û�� @Expose ע����ֶ�
			mGson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
		return mGson;
	}

	public DbUtil getDbHelper() {
		if (mDbHelper == null)
			initDbHelper(this);
		return mDbHelper;
	}
	public NotificationManager getNotificationManager() {
		if (mNotificationManager == null)
			mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
		return mNotificationManager;
	}

	public synchronized SharePreferenceUtil getSpUtil() {
		if (mSpUtil == null)
			mSpUtil = new SharePreferenceUtil(this, ApplicationConfig.SP_FILE_NAME);
		return mSpUtil;
	}

	private static E_ARM_INTYPE getArmInType() {
		try {
			FileReader fr = new FileReader("/proc/cpuinfo");
			BufferedReader localBufferedReader = new BufferedReader(fr, 8192);
			char[] data = new char[1024];
			localBufferedReader.read(data);
			localBufferedReader.close();
			int architecture = 5;
			final String cpuInfo = new String(data).toLowerCase();

			if (cpuInfo.contains("neon")) {
				return E_ARM_INTYPE.neon;
			} else {
				outputLog(TAG, cpuInfo);
				int index = cpuInfo.indexOf("cpu architecture:");
				index += "cpu architecture:".length();

				for (int i = index; i < cpuInfo.length(); i++) {
					char a = cpuInfo.charAt(i);
					if (a <= '9' && a >= '0') {
						architecture = a - '0';
						break;
					}
				}
				outputLog(TAG, "architecture " + architecture);
				if (architecture <= 5) {
					return E_ARM_INTYPE.arm9e;
				} else {
					return E_ARM_INTYPE.arm11;
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return E_ARM_INTYPE.arm9e;
	}

	private static void outputLog(String strTAG, String strInfo) {
		LogUtil.i(strTAG, strInfo);
	}

	private void CheckCPUinfo() {
		ProcessBuilder cmd;
		String result = "";

		try {
			String[] args = {"/system/bin/cat", "/proc/cpuinfo"};
			cmd = new ProcessBuilder(args);

			Process process = cmd.start();
			InputStream in = process.getInputStream();
			byte[] re = new byte[1024];
			while (in.read(re) != -1) {
				System.out.println(new String(re));
				result = result + new String(re);
			}
			in.close();
		} catch (IOException ex) {
			ex.printStackTrace();
		}
		Log.i("CPUID", result);
		return;
	}

	private String getCurAppDir() {
		ApplicationInfo applicationInfo = getApplicationInfo();
		LogUtil.d(TAG, "cur data dir:" + this.getApplicationInfo().dataDir);
		LogUtil.d(TAG, "cur file dir:" + getBaseContext().getFilesDir().getAbsolutePath());

		_strLibsDir = applicationInfo.dataDir;
		_strFileDir = getBaseContext().getFilesDir().getAbsolutePath();

		if (!_strLibsDir.endsWith("/")) {
			_strLibsDir = _strLibsDir + "/";
		}
		_strLibsDir = _strLibsDir + "lib/";
		LogUtil.d(TAG, "cur libs dir:" + _strLibsDir);

		if (!_strFileDir.endsWith("/")) {
			_strFileDir = _strFileDir + "/";
		}
		LogUtil.d(TAG, "cur file dir:" + _strFileDir);
		return this.getApplicationInfo().dataDir;
	}

	private void copyPlayerIni() {
		getCurAppDir();

		ArrayList<Integer> codecList = new ArrayList<Integer>();
		codecList.add(ModuleManager.CODEC_SUBTYPE_H264);
		codecList.add(ModuleManager.CODEC_SUBTYPE_MP3);
		codecList.add(ModuleManager.CODEC_SUBTYPE_AAC);
		// WARNING: DO NOT USE CODEC_SUBTYPE_ALL if you expect smaller config
		// file size
		codecList.add(ModuleManager.CODEC_SUBTYPE_ALL);

		ArrayList<Integer> parserList = new ArrayList<Integer>();
		parserList.add(ModuleManager.FILE_PARSER_SUBTYPE_MP4);
		parserList.add(ModuleManager.FILE_PARSER_SUBTYPE_FLV);
		parserList.add(ModuleManager.FILE_PARSER_SUBTYPE_AVI);
		parserList.add(ModuleManager.FILE_PARSER_SUBTYPE_MKV);
		parserList.add(ModuleManager.FILE_PARSER_SUBTYPE_ASF_STREAMING);
		parserList.add(ModuleManager.FILE_PARSER_SUBTYPE_OGG);
		parserList.add(ModuleManager.FILE_PARSER_SUBTYPE_AAC);
		parserList.add(ModuleManager.FILE_PARSER_SUBTYPE_MP3);
		parserList.add(ModuleManager.FILE_PARSER_SUBTYPE_TS);
		parserList.add(ModuleManager.FILE_PARSER_SUBTYPE_MP2);
		parserList.add(ModuleManager.FILE_PARSER_SUBTYPE_RM);
		parserList.add(ModuleManager.FILE_PARSER_SUBTYPE_FLAC);
		// parserList.add(ModuleManager.FILE_PARSER_SUBTYPE_TS_STREAMING);
		parserList.add(ModuleManager.FILE_PARSER_SUBTYPE_ALL);

		ModuleManager mgr = new ModuleManager(null, codecList, parserList);
		ArrayList<String> modList = mgr.QueryRequiredModules();
		E_ARCH_TYPE archType = mgr.getCPUArchType();
		outputLog(TAG, "module list(" + modList.size() + ": " + modList);

		File dirFile = new File(_strFileDir);
		if (!dirFile.exists()) {
			if (!dirFile.mkdirs()) {
				return;
			}
		}

		mgr.GenerateConfigFile(_strLibsDir, _strFileDir + "MV3Plugin.ini");
	}

	private static void LoadLibraray() {
		System.load(_strLibsDir + "libmv3_platform.so");
		System.load(_strLibsDir + "libmv3_common.so");
		System.load(_strLibsDir + "libmv3_mpplat.so");
		try {
			System.load(_strLibsDir + "libmv3_playerbase.so");
		} catch (UnsatisfiedLinkError ex) {
			Log.d(TAG, "load libmv3_playerbase.so failed");
		}
		try {
			System.load(_strLibsDir + "libmv3_jni_4.0.so");
		} catch (UnsatisfiedLinkError ex) {
			Log.d(TAG, "load libmv3_jni_4.0.so failed");
		}
		try {
			System.load(_strLibsDir + "libmv3_jni.so");
		} catch (UnsatisfiedLinkError ex) {
			Log.d(TAG, "load libmv3_jni.so failed");
		}
	}
}
